package com.shine.app.widget.rangebar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.shine.app.R;

public class RangeBar extends View {

	private int tickCount = 3;
	private float tickHeightDP = 0;
	private float barWeight = 4;
	private int barColor = 0xff33b5e5;
	private float connectingLineWeight = 100;
	private int connectingLineColor = Color.LTGRAY;
	private int thumbImageNormal = R.drawable.rangebar_circle;
	private int thumbImagePressed = R.drawable.rangebar_circle;
	private float thumbRadiusDP = -1;
	private int thumbColorNormal = -1;
	private int thumbColorPressed = -1;
	private boolean firstSetTickCount = true;
	private int defaultWidth = 500;
	private int defaultHeight = 100;
	private Thumb leftThumb;
	private Thumb rightThumb;
	private Bar bar;
	private ConnectingLine connectingLine;
	private RangeBar.OnRangeBarChangeListener rangeBarChangeListener;
	private int leftIndex = 0;
	private int rightIndex = tickCount - 1;

	public RangeBar(Context context) {
		super(context);
	}

	public RangeBar(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public RangeBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int width;
		int height;
		final int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
		final int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
		final int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
		final int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
		if (measureWidthMode == MeasureSpec.AT_MOST) {
			width = measureWidth;
		} else if (measureWidthMode == MeasureSpec.EXACTLY) {
			width = measureWidth;
		} else {
			width = defaultWidth;
		}
		if (measureHeightMode == MeasureSpec.AT_MOST) {
			height = Math.min(defaultHeight, measureHeight);
		} else if (measureHeightMode == MeasureSpec.EXACTLY) {
			height = measureHeight;
		} else {
			height = defaultHeight;
		}
		setMeasuredDimension(width, height);
	}

	@Override
	protected void onSizeChanged(int width, int height, int oldWidth,
			int oldHeight) {
		super.onSizeChanged(width, height, oldWidth, oldHeight);
		final Context context = getContext();
		final float yPos = height / 2f;
		leftThumb = new Thumb(context, yPos, thumbColorNormal,
				thumbColorPressed, thumbRadiusDP, thumbImageNormal,
				thumbImagePressed);
		rightThumb = new Thumb(context, yPos, thumbColorNormal,
				thumbColorPressed, thumbRadiusDP, thumbImageNormal,
				thumbImagePressed);
		final float marginLeft = leftThumb.getHalfWidth();
		final float barLength = width - 2 * marginLeft;
		bar = new Bar(context, marginLeft, yPos, barLength, tickCount,
				tickHeightDP, barWeight, barColor);
		leftThumb.setX(marginLeft + (leftIndex / (float) (tickCount - 1))
				* barLength);
		rightThumb.setX(marginLeft + (rightIndex / (float) (tickCount - 1))
				* barLength);
		final int newLeftIndex = bar.getNearestTickIndex(leftThumb);
		final int newRightIndex = bar.getNearestTickIndex(rightThumb);
		if (newLeftIndex != leftIndex || newRightIndex != rightIndex) {
			leftIndex = newLeftIndex;
			rightIndex = newRightIndex;
			if (rangeBarChangeListener != null) {
				rangeBarChangeListener.onIndexChangeListener(this, leftIndex,
						rightIndex);
			}
		}
		connectingLine = new ConnectingLine(context, yPos,
				connectingLineWeight, connectingLineColor);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		bar.draw(canvas);
		connectingLine.draw(canvas, leftThumb, rightThumb);
		leftThumb.draw(canvas);
		rightThumb.draw(canvas);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (!isEnabled()) {
			return false;
		}
		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:
			onActionDown(event.getX(), event.getY());
			return true;

		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			this.getParent().requestDisallowInterceptTouchEvent(false);
			onActionUp();
			return true;

		case MotionEvent.ACTION_MOVE:
			onActionMove(event.getX());
			this.getParent().requestDisallowInterceptTouchEvent(true);
			return true;

		default:
			return false;
		}
	}

	public void setOnRangeBarChangeListener(
			RangeBar.OnRangeBarChangeListener listener) {
		rangeBarChangeListener = listener;
	}

	public void setTickCount(int count) {
		if (isValidTickCount(count)) {
			tickCount = count;
			if (firstSetTickCount) {
				leftIndex = 0;
				rightIndex = tickCount - 1;
				if (rangeBarChangeListener != null) {
					rangeBarChangeListener.onIndexChangeListener(this,
							leftIndex, rightIndex);
				}
			}
			if (indexOutOfRange(leftIndex, rightIndex)) {
				leftIndex = 0;
				rightIndex = tickCount - 1;
				if (rangeBarChangeListener != null)
					rangeBarChangeListener.onIndexChangeListener(this,
							leftIndex, rightIndex);
			}
			createBar();
			createThumbs();
		} else {
			throw new IllegalArgumentException(
					"tickCount less than 2; invalid tickCount.");
		}
	}

	public void setTickHeight(float tickHeight) {
		tickHeightDP = tickHeight;
		createBar();
	}

	public void setBarWeight(float weight) {
		barWeight = weight;
		createBar();
	}

	public void setBarColor(int color) {
		barColor = color;
		createBar();
	}

	public void setConnectingLineWeight(float lineWeight) {
		connectingLineWeight = lineWeight;
		createConnectingLine();
	}

	public void setConnectingLineColor(int lineColor) {
		connectingLineColor = lineColor;
		createConnectingLine();
	}

	public void setThumbRadius(float thumbRadius) {
		thumbRadiusDP = thumbRadius;
		createThumbs();
	}

	public void setThumbImageNormal(int thumbImageNormalID) {
		thumbImageNormal = thumbImageNormalID;
		createThumbs();
	}

	public void setThumbImagePressed(int thumbImagePressedID) {
		thumbImagePressed = thumbImagePressedID;
		createThumbs();
	}

	public void setThumbColorNormal(int thumbColor) {
		thumbColorNormal = thumbColor;
		createThumbs();
	}

	public void setThumbColorPressed(int thumbColor) {
		thumbColorPressed = thumbColor;
		createThumbs();
	}

	public void setThumbIndices(int leftThumbIndex, int rightThumbIndex) {
		if (indexOutOfRange(leftThumbIndex, rightThumbIndex)) {
			throw new IllegalArgumentException(
					"A thumb index is out of bounds. Check that it is between 0 and mTickCount - 1");
		} else {
			if (firstSetTickCount == true)
				firstSetTickCount = false;
			leftIndex = leftThumbIndex;
			rightIndex = rightThumbIndex;
			createThumbs();
			if (rangeBarChangeListener != null) {
				rangeBarChangeListener.onIndexChangeListener(this, leftIndex,
						rightIndex);
			}
		}
		invalidate();
		requestLayout();
	}

	public int getLeftIndex() {
		return leftIndex;
	}

	public int getRightIndex() {
		return rightIndex;
	}

	private void createBar() {
		bar = new Bar(getContext(), getMarginLeft(), getYPos(), getBarLength(),
				tickCount, tickHeightDP, barWeight, barColor);
		invalidate();
	}

	private void createConnectingLine() {
		connectingLine = new ConnectingLine(getContext(), getYPos(),
				connectingLineWeight, connectingLineColor);
		invalidate();
	}

	private void createThumbs() {
		Context context = getContext();
		float yPos = getYPos();
		leftThumb = new Thumb(context, yPos, thumbColorNormal,
				thumbColorPressed, thumbRadiusDP, thumbImageNormal,
				thumbImagePressed);
		rightThumb = new Thumb(context, yPos, thumbColorNormal,
				thumbColorPressed, thumbRadiusDP, thumbImageNormal,
				thumbImagePressed);
		float marginLeft = getMarginLeft();
		float barLength = getBarLength();
		leftThumb.setX(marginLeft + (leftIndex / (float) (tickCount - 1))
				* barLength);
		rightThumb.setX(marginLeft + (rightIndex / (float) (tickCount - 1))
				* barLength);
		invalidate();
	}

	private float getMarginLeft() {
		return ((leftThumb != null) ? leftThumb.getHalfWidth() : 0);
	}

	private float getYPos() {
		return (getHeight() / 2f);
	}

	private float getBarLength() {
		return (getWidth() - 2 * getMarginLeft());
	}

	private boolean indexOutOfRange(int leftThumbIndex, int rightThumbIndex) {
		return (leftThumbIndex < 0 || leftThumbIndex >= tickCount
				|| rightThumbIndex < 0 || rightThumbIndex >= tickCount);
	}

	private boolean isValidTickCount(int tickCount) {
		return (tickCount > 1);
	}

	private void onActionDown(float x, float y) {
		if (!leftThumb.isPressed() && leftThumb.isInTargetZone(x, y)) {
			pressThumb(leftThumb);
		} else if (!leftThumb.isPressed() && rightThumb.isInTargetZone(x, y)) {
			pressThumb(rightThumb);
		}
	}

	private void onActionUp() {
		if (leftThumb.isPressed()) {
			releaseThumb(leftThumb);
		} else if (rightThumb.isPressed()) {
			releaseThumb(rightThumb);
		}
	}

	private void onActionMove(float x) {
		if (leftThumb.isPressed()) {
			moveThumb(leftThumb, x);
		} else if (rightThumb.isPressed()) {
			moveThumb(rightThumb, x);
		}
		if (leftThumb.getX() > rightThumb.getX()) {
			final Thumb temp = leftThumb;
			leftThumb = rightThumb;
			rightThumb = temp;
		}
		final int newLeftIndex = bar.getNearestTickIndex(leftThumb);
		final int newRightIndex = bar.getNearestTickIndex(rightThumb);
		if (newLeftIndex != leftIndex || newRightIndex != rightIndex) {
			leftIndex = newLeftIndex;
			rightIndex = newRightIndex;
			if (rangeBarChangeListener != null) {
				rangeBarChangeListener.onIndexChangeListener(this, leftIndex,
						rightIndex);
			}
		}
	}

	private void pressThumb(Thumb thumb) {
		if (firstSetTickCount == true)
			firstSetTickCount = false;
		thumb.press();
		invalidate();
	}

	private void releaseThumb(Thumb thumb) {
		final float nearestTickX = bar.getNearestTickCoordinate(thumb);
		thumb.setX(nearestTickX);
		thumb.release();
		invalidate();
	}

	private void moveThumb(Thumb thumb, float x) {
		if (x < bar.getLeftX() || x > bar.getRightX()) {
		} else {
			thumb.setX(x);
			invalidate();
		}
	}

	public static interface OnRangeBarChangeListener {
		public void onIndexChangeListener(RangeBar rangeBar,
				int leftThumbIndex, int rightThumbIndex);
	}

	public float getTickHeightDP() {
		return tickHeightDP;
	}

	public void setTickHeightDP(float tickHeightDP) {
		this.tickHeightDP = tickHeightDP;
	}

	public float getThumbRadiusDP() {
		return thumbRadiusDP;
	}

	public void setThumbRadiusDP(float thumbRadiusDP) {
		this.thumbRadiusDP = thumbRadiusDP;
	}

	public boolean isFirstSetTickCount() {
		return firstSetTickCount;
	}

	public void setFirstSetTickCount(boolean firstSetTickCount) {
		this.firstSetTickCount = firstSetTickCount;
	}

	public int getDefaultWidth() {
		return defaultWidth;
	}

	public void setDefaultWidth(int defaultWidth) {
		this.defaultWidth = defaultWidth;
	}

	public int getDefaultHeight() {

		return defaultHeight;
	}

	public void setDefaultHeight(int defaultHeight) {
		this.defaultHeight = defaultHeight;
	}

	public Thumb getLeftThumb() {
		return leftThumb;
	}

	public void setLeftThumb(Thumb leftThumb) {
		this.leftThumb = leftThumb;
	}

	public Thumb getRightThumb() {
		return rightThumb;
	}

	public void setRightThumb(Thumb rightThumb) {
		this.rightThumb = rightThumb;
	}

	public Bar getBar() {
		return bar;
	}

	public void setBar(Bar bar) {
		this.bar = bar;
	}

	public ConnectingLine getConnectingLine() {
		return connectingLine;
	}

	public void setConnectingLine(ConnectingLine connectingLine) {
		this.connectingLine = connectingLine;
	}

	public RangeBar.OnRangeBarChangeListener getmListener() {
		return rangeBarChangeListener;
	}

	public void setmListener(RangeBar.OnRangeBarChangeListener listener) {
		this.rangeBarChangeListener = listener;
	}

	public int getTickCount() {
		return tickCount;
	}

	public float getBarWeight() {
		return barWeight;
	}

	public int getBarColor() {
		return barColor;
	}

	public float getConnectingLineWeight() {
		return connectingLineWeight;
	}

	public int getConnectingLineColor() {
		return connectingLineColor;
	}

	public int getThumbImageNormal() {
		return thumbImageNormal;
	}

	public int getThumbImagePressed() {
		return thumbImagePressed;
	}

	public int getThumbColorNormal() {
		return thumbColorNormal;
	}

	public int getThumbColorPressed() {
		return thumbColorPressed;
	}

	public void setLeftIndex(int leftIndex) {
		this.leftIndex = leftIndex;
	}

	public void setRightIndex(int rightIndex) {
		this.rightIndex = rightIndex;
	}

}
